package server;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import server.interfaces.ExceptionHolder;
import server.interfaces.ExceptionObserver;

/**
 * <h1>Class LogException</h1>
 * 
 * Stores all the exception which happens in the server in order to be visualized
 * via a GUI and allow the developers to debug the system.
 * Follows the singleton pattern to have all the exceptions logged in the same place.
 * 
 * @author Tomas
 * @date March 8 2009
 */
public class LogException implements ExceptionHolder{

	/**
	 * Collection of all the exceptions happened.
	 * To be implemented as an ArrayList
	 */
	protected List<Exception> exceptions = null;
	
	/**
	 * Single instance of the class.
	 */
	private static LogException instance = null;
	
	/**
	 * Collection of observers to be notified when changes happen in the
	 * instance.
	 * To be implemented as an ArrayList.
	 */
	protected List<ExceptionObserver> observers = null;
	
	/**
	 * Default constructor. Initializes the single instance of the class.
	 */
	private LogException(){
		
		exceptions = new ArrayList<Exception>();
		observers = new ArrayList<ExceptionObserver>();
		
	}
	
	/**
	 * Obtains the single instance of the class.
	 * 
	 * @return
	 * 		Single instance of the class.
	 */
	public synchronized static LogException getInstance(){

		if(instance == null){
			instance = new LogException();
		}
		
		return instance;
		
	}
	
	/**
	 * Stores an exception.
	 * 
	 * @param e
	 * 		Exception to be stored.
	 */
	public synchronized void logException(Exception e){
		
		exceptions.add(e);
		notifyObservers();
		
	}
	
	/**
	 * Obtains all the exceptions happened in the server.
	 * 
	 * @return
	 * 		Iterator over the collection of exceptions happened in the server.
	 */
	public synchronized Iterator<Exception> getExceptions(){
		
		return exceptions.iterator();
		
	}
	
	/**
	 * Obtains a certain exception.
	 * 
	 * @param pos
	 * 		Position of the exception to be retrieved.
	 * @return
	 * 		Exception in such position, if any, or null.
	 */
	public synchronized Exception getException(int pos){
		
		if(pos >= 0 && pos < exceptions.size()){
			return exceptions.get(pos);
		}else{
			return null;
		}
		
	}
	
	/**
	 * Removes all the exceptions.
	 */
	public synchronized void clear(){
		
		exceptions.clear();
		notifyObservers();
		
	}

	@Override
	/**
	 * @see server.interfaces.ExceptionObserver
	 */
	public void subscribe(ExceptionObserver observer) {
		
		observers.add(observer);
		observer.updateExceptions();
		
	}

	@Override
	/**
	 * @see server.interfaces.ExceptionObserver
	 */
	public void unsubscribe(ExceptionObserver observer) {
		
		observers.remove(observer);
		
	}
	
	/**
	 * Notifies all the observers about changes in the instance.
	 */
	protected void notifyObservers(){
		
		Iterator<ExceptionObserver> it = observers.iterator();
		
		while(it.hasNext()){
			ExceptionObserver eo = it.next();
			eo.updateExceptions();
		}
	}
}
